
#ifndef _EVENT_T_H_
#define _EVENT_T_H_

#include <map>
#include <assert.h>

namespace KCore
{
	
	class IEvent
	{
	public:
	
	};


	template<typename Event>
	class EventInfo;

#define DEFINE_EVENT_ID(event_id,Event)\
	class Event;\
	template<>\
	class EventInfo<Event>\
	{\
	enum{id = event_id};\
	public:\
	static const int getID()\
	{\
	return id;\
	}\
	};\
	
	struct EVENT_PARAM 
	{
		unsigned int event_id;
		IEvent* pEventHandler;
	};

	template<typename Event>
	EVENT_PARAM GetEventParam(Event* pEventHandler)
	{
		EVENT_PARAM stEvent = {EventInfo<Event>::getID(),pEventHandler};
		return stEvent;
	}

	class IEventProducer
	{
	public:
		virtual void addEventHandler(EVENT_PARAM& stEventHandler) = 0;
		virtual void removeEventHandler(EVENT_PARAM& stEventHandler) = 0;
	};

	
	template<typename EventProducer = IEventProducer>
	class TEvenetProducerImpl : public EventProducer
	{
	private:
		typedef std::multimap<unsigned int, IEvent*> EVENTID2EVENTLISTMAP;
		typedef EVENTID2EVENTLISTMAP::iterator EVENTLIST_ITERATOR;
		typedef std::pair<EVENTLIST_ITERATOR, EVENTLIST_ITERATOR> EVENTLIST_ITERATOR_PAIR;

		EVENTID2EVENTLISTMAP m_mapEventID2EventList;
	public:
		virtual ~TEvenetProducerImpl(){};

		virtual void addEventHandler(EVENT_PARAM& stEventHandler)
		{
			m_mapEventID2EventList.insert(std::make_pair(stEventHandler.event_id, stEventHandler.pEventHandler));
		}

		virtual void removeEventHandler(EVENT_PARAM& stEventHandler)
		{
			EVENTLIST_ITERATOR it = m_mapEventID2EventList.find(stEventHandler.event_id);

			for(; it != m_mapEventID2EventList.end(); ++it)
			{
				if (it->second == stEventHandler.pEventHandler) 
				{
					m_mapEventID2EventList.erase(it);
					break;
				}
			}
		}


	protected:
		template<typename EventTypeList, typename EventType> inline
		void safeProtectFireEvent(EventTypeList& listEventHandler, EVENTLIST_ITERATOR_PAIR& itePair, EventType* pDummy)
		{
			for(; itePair.first != itePair.second; ++itePair.first)
			{
				IEvent* handerAddress = itePair.first->second;
				EventType* pEventHandler = static_cast<EventType*>(handerAddress);

				listEventHandler.push_back(pEventHandler);
			}
		}

		template<typename EventTypeList,typename EventType> inline
		bool prepareEventHandlerList(EventTypeList& listEventHandler, EventType* pDummy)
		{
			bool bPrepare = false;
			unsigned int eventID = EventInfo<EventType>::getID();

			EVENTLIST_ITERATOR_PAIR itePair = m_mapEventID2EventList.equal_range(eventID);

			if (itePair.first != itePair.second) 
			{
				safeProtectFireEvent(listEventHandler, itePair, pDummy);
				bPrepare = true;
			}

			return bPrepare;
		}


		#define FIREEVENT_IMPLEMENT(expression)\
		Type* pDummy = 0;\
		std::list<Type*>  listEventHandler;\
		\
		if (prepareEventHandlerList(listEventHandler, pDummy)) \
		{\
			for(std::list<Type*>::iterator it = listEventHandler.begin();\
			it != listEventHandler.end(); ++it)\
			{\
				Type* pEventHandler = *it;\
				\
				expression;\
			}\
		}else{\
			assert(0);\
		}\


	public:
		// 0 argument
		template<class Type> inline
		void fireEvent(void (Type::*EventName)())
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)());
		}

		// 1 argument
		template<class Type, class ArgT> inline
		void fireEvent(void (Type::*EventName)(ArgT), ArgT& arg)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg));		
		}

		// 2 arguments
		template<class Type, class Arg1T, class Arg2T> inline
		void fireEvent(void (Type::*EventName)(Arg1T, Arg2T),
			 Arg1T& arg1,  Arg2T& arg2)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg1, arg2));
		}

		// 3 arguments
		template<class Type, class Arg1T, class Arg2T, class Arg3T> inline
		void fireEvent(void (Type::*EventName)(Arg1T, Arg2T, Arg3T),
			 Arg1T& arg1,  Arg2T& arg2,  Arg3T& arg3)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg1, arg2, arg3));
		}

		// 4 arguments
		template<class Type, class Arg1T, class Arg2T, class Arg3T, class Arg4T> inline
		void fireEvent(void (Type::*EventName)(Arg1T, Arg2T, Arg3T, Arg4T),
			 Arg1T& arg1,  Arg2T& arg2,  Arg3T& arg3,  Arg4T& arg4)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg1, arg2, arg3, arg4));
		}

		// 5 arguments
		template<class Type, class Arg1T, class Arg2T, class Arg3T, class Arg4T, class Arg5T> inline
		void fireEvent(void (Type::*EventName)(Arg1T, Arg2T, Arg3T, Arg4T, Arg5T),
			 Arg1T& arg1,  Arg2T& arg2,  Arg3T& arg3,
			 Arg4T& arg4,  Arg5T& arg5)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg1, arg2, arg3, arg4, arg5));
		}

		// 6 arguments
		template<class Type, class Arg1T, class Arg2T, class Arg3T, class Arg4T, class Arg5T, class Arg6T> inline
		void fireEvent(void (Type::*EventName)(Arg1T, Arg2T, Arg3T, Arg4T, Arg5T, Arg6T),
			 Arg1T& arg1,  Arg2T& arg2,  Arg3T& arg3,
			 Arg4T& arg4,  Arg5T& arg5,  Arg6T& arg6)
		{
			FIREEVENT_IMPLEMENT((pEventHandler->*EventName)(arg1, arg2, arg3, arg4, arg5, arg6));
		}
	};

};

#endif

